package val.to.UI;

import java.text.SimpleDateFormat;
import java.util.ArrayList;
import val.to.ErrorHelper;
import val.to.Globals;
import val.to.R;
import val.to.SessionEvents;
import val.to.Utility;
import val.to.ValtoActivity;
import val.to.ValtoServices;
import val.to.SessionEvents.LogoutListener;
import val.to.common.SingleItemViewAdapter;
import val.to.entities.Event;
import val.to.hardware.location.LocationProvider;
import val.to.hardware.location.LocationProvider.ILocationListener;
import android.app.AlertDialog;
import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent;
import android.location.Location;
import android.os.Bundle;
import android.os.Handler;
import android.view.LayoutInflater;
import android.view.View;
import android.view.View.OnClickListener;
import android.view.ViewGroup;
import android.view.ViewGroup.LayoutParams;
import android.view.WindowManager;
import android.widget.AdapterView;
import android.widget.AdapterView.OnItemClickListener;
import android.widget.BaseAdapter;
import android.widget.EditText;
import android.widget.ImageButton;
import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.ListView;
import android.widget.TextView;
import android.widget.Toast;

public class EventsActivity extends ValtoActivity {

	public enum NavigationType {
		EventDetails, EventNewsFeed
	}

	private Handler mHandler;
	private ListView mEventList;
	private LocationProvider mLocationProvider;
	private ImageButton mRefreshBtn;
	private MenuButton mMenuButton;
	private boolean quickUpload;
	private boolean mRefreshOnResume = true;

	private class LocationListener implements ILocationListener {

		/**
		 * Executes on the main thread.
		 */
		@Override
		public void onLocationReady(final Location location) {

			// Refresh the feed
			new Thread(new Runnable() {
				@Override
				public void run() {
					refreshEvents(location);
				}
			}).start();
		}

		@Override
		public void onTimeout() {
			onFailed();
		}

		@Override
		public void onError() {
			onFailed();
		}

		private void onFailed() {
			ErrorHelper.showErrorAlert(EventsActivity.this,
					"Failed to obtain current location", null);
			mEventList.setAdapter(null);
		}
	}

	@Override
	public void onNewIntent(Intent intent) {
		String s = intent.getStringExtra("quickUpload");
		quickUpload = s != null;

	}

	@Override
	public void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		setContentView(R.layout.events_list);

		mHandler = new Handler();
		mLocationProvider = new LocationProvider(this);
		mLocationProvider.addListener(new LocationListener());

		String s = getIntent().getStringExtra("quickUpload");
		quickUpload = s != null;

		InitUIComponents();
		
		SessionEvents.addLogoutListener(new LogoutListener() {
			@Override
			public void onLogoutFinish() {
				mEventList.setAdapter(null);
				mRefreshOnResume = true;
			}

			@Override
			public void onLogoutBegin() {
			}
		});
	}

	private void InitUIComponents() {
		// connect UI components to local variables
		mEventList = (ListView) findViewById(R.id.eventList);

		mMenuButton = (MenuButton) findViewById(R.id.menuButton);
		mMenuButton.init(this);
		if (quickUpload)
			mMenuButton.setVisibility(View.INVISIBLE);

		mRefreshBtn = (ImageButton) findViewById(R.id.refresh);
		mRefreshBtn.setOnClickListener(new OnClickListener() {
			@Override
			public void onClick(View v) {
				getNearbyEvents();
			}
		});

		mEventList.setOnItemClickListener(new OnItemClickListener() {
			@Override
			public void onItemClick(AdapterView<?> adapterView, View view,
					int position, long l) {

				Event event = (Event) adapterView.getAdapter()
						.getItem(position);
				GetEventAccessPermission(event, NavigationType.EventNewsFeed,
						view.getContext());
			}
		});

	}

	@Override
	public void onResume() {
		super.onResume();

		if (quickUpload)
			mMenuButton.setVisibility(View.INVISIBLE);
		else
			mMenuButton.setVisibility(View.VISIBLE);
		BaseAdapter adapter = (BaseAdapter) mEventList.getAdapter();
		if (adapter != null)
			adapter.notifyDataSetChanged();

		// if session is valid get user's info (currently just the display name)
		if (Globals.FacebookSession.isSessionValid()) {
			if (mRefreshOnResume) {
				getNearbyEvents();
				mRefreshOnResume = false;
			}
		} else {
			onLoggedOut();
			mRefreshOnResume = true;
		}

		mRefreshBtn.setEnabled(Globals.FacebookSession.isSessionValid());
	}

	private void onLoggedOut() {
		mEventList.setAdapter(new SingleItemViewAdapter(this,
				R.string.LoginFirst, false));
	}

	@Override
	public void onActivityResult(int requestCode, int resultCode, Intent data) {
		super.onActivityResult(requestCode, resultCode, data);
		// Nothing here for now
	}

	// calls GetNearbyEventsTask.execute() if no previous call of
	// GetNearbyEventsTask.execute is running
	private void getNearbyEvents() {
		mEventList.setAdapter(new SingleItemViewAdapter(this, R.string.Loading,
				true));
		mLocationProvider.start();
	}

	/**
	 * This method runs on background thread.
	 */
	private void refreshEvents(Location location) {

		final ArrayList<Event> items = ValtoServices.getEvents(location);

		mHandler.post(new Runnable() {
			@Override
			public void run() {
				// Go back to the UI Thread.
				if (items == null) {
					mEventList.setAdapter(new SingleItemViewAdapter(
							EventsActivity.this, R.string.error_loading_events,
							false, R.drawable.error_bw, ValtoServices
									.getLastServerError()));
					return;
				}

				if (items.size() > 0) {
					mEventList.setAdapter(new EventItemAdapter(items));
				} else {
					mEventList.setAdapter(new SingleItemViewAdapter(
							EventsActivity.this, R.string.no_events, false));
				}
			}
		});
	}

	private class EventItemAdapter extends BaseAdapter {

		private ArrayList<Event> m_items;
		private LayoutInflater m_inflater;
		private SimpleDateFormat m_formatter = new SimpleDateFormat("HH:mm");

		public EventItemAdapter(ArrayList<Event> items) {
			m_items = items;
			m_inflater = (LayoutInflater) EventsActivity.this
					.getLayoutInflater();
		}

		@Override
		public int getCount() {
			return m_items.size();
		}

		@Override
		public Object getItem(int arg0) {
			return m_items.get(arg0);
		}

		@Override
		public long getItemId(int position) {
			return m_items.get(position).getId();
		}

		@Override
		public View getView(int position, View convertView, ViewGroup parent) {
			if (convertView == null) {
				convertView = m_inflater.inflate(R.layout.event_item, null);
			}
			
			TextView name = (TextView) convertView.findViewById(R.id.name);
			TextView desc = (TextView) convertView.findViewById(R.id.description);
			TextView time = (TextView) convertView.findViewById(R.id.label_time);
			TextView checkIn = (TextView) convertView.findViewById(R.id.label_checkin);
			ImageView aboutButton = (ImageView) convertView.findViewById(R.id.about);
			ImageView thumbnail = (ImageView) convertView.findViewById(R.id.thumbnail);

			Event event = m_items.get(position);

			if (quickUpload){
				aboutButton.setVisibility(View.INVISIBLE);
			}
				
			if (event.getPassword().equals(Event.NO_PASSWORD)){
				thumbnail.setImageResource(R.drawable.event_nopic);		
			}
			else{
				thumbnail.setImageResource(R.drawable.event_nopic_locked);
			}
			
			name.setText(event.getName());
			desc.setText(event.getDescription().length() == 0 ? "" : event.getDescription() + " ");
			
			String dayDiffStart = Utility.getDayDiffFromNowAsString(event.getStartDate());
			String timeTextStart =  m_formatter.format(event.getStartDate());
			String dayDiffEnd = Utility.getDayDiffFromNowAsString(event.getEndTime());
			String timeTextEnd =  m_formatter.format(event.getEndTime());
			
			dayDiffStart = dayDiffStart == null ? "at " : dayDiffStart + " at ";
			dayDiffEnd = dayDiffEnd == null ? "at " : dayDiffEnd + " at ";
			
			String template = getResources().getString(R.string.event_item_time_template);
			String timeText = String.format(template, dayDiffStart + timeTextStart, dayDiffEnd + timeTextEnd);
			time.setText(timeText);
			
			template = getResources().
				getString(ValtoServices.isCheckedIntoEvent(event.getId()) ? 
						R.string.event_item_checkin_with_user : R.string.events_item_checkin);
			checkIn.setText(String.format(template, event.getCheckedInUsers()));
			
			aboutButton.setTag(event);
			aboutButton.setOnClickListener(new View.OnClickListener() {
				@Override
				public void onClick(View v) {
					Event event = (Event) v.getTag();
					GetEventAccessPermission(event,
							NavigationType.EventDetails, v.getContext());
				}
			});

			return convertView;
		}
	}

	private boolean NavigateTo(Event event, NavigationType navigation,
			Context context) {
		if (navigation == NavigationType.EventDetails) {
			Intent intent = new Intent(context, EventDetailsActivity.class);
			intent.putExtra("source", EventsActivity.class.getName());

			Bundle b = new Bundle();
			b.putParcelable("val.to.entities.Event", event);

			intent.putExtras(b);
			startActivity(intent);
		} else if (navigation == NavigationType.EventNewsFeed) {
			ValtoServices.selectEvent(event);
			if (quickUpload) {
				finish();
			} else {
				Intent intent = new Intent(context, NewsFeed.class);
				startActivity(intent);
			}
		}

		return true;
	}

	private boolean GetEventAccessPermission(Event event,
			NavigationType navigation, Context context) {
		if (event.getPassword().equals(Event.NO_PASSWORD)
				|| Globals.PasswordsStore
						.IsSavedPasswordForEvent(event.getId()))
			return NavigateTo(event, navigation, context);

		// Ask the user for password
		AlertDialog dialog = CreatePasswordDialog(event, navigation, context);
		dialog.show();

		return true;
	}

	private AlertDialog CreatePasswordDialog(final Event event,
			final NavigationType navigation, final Context context) {
		LinearLayout layout = new LinearLayout(this);
		layout.setPadding(10, 10, 10, 10);
		final EditText et = new EditText(this);
		et.setLayoutParams(new LayoutParams(LayoutParams.FILL_PARENT,
				LayoutParams.WRAP_CONTENT));

		layout.addView(et);

		AlertDialog.Builder builder = new AlertDialog.Builder(this);
		builder.setView(layout);
		builder.setTitle("Enter a Password for " + event.getName() + ":");

		builder.setPositiveButton("OK", new DialogInterface.OnClickListener() {
			@Override
			public void onClick(DialogInterface dialog, int which) {
				if (EnterPasswordToEvent(event, et.getText().toString()))
					NavigateTo(event, navigation, context);
				else
					Toast.makeText(context, "Incorrect Password.",
							Toast.LENGTH_SHORT).show();
			}
		});
		builder.setNegativeButton("Cancel", null);
		final AlertDialog ad = builder.create();
		et.setOnFocusChangeListener(new View.OnFocusChangeListener() {
			public void onFocusChange(View v, boolean hasFocus) {
				if (hasFocus) {
					ad.getWindow()
							.setSoftInputMode(
									WindowManager.LayoutParams.SOFT_INPUT_STATE_ALWAYS_VISIBLE);
				}
			}
		});
		et.requestFocus();
		return ad;
	}

	private boolean EnterPasswordToEvent(final Event m, final String password) {
		String passHashed = Utility.md5(password);

		if (m.getPassword().equals(passHashed)) {
			Globals.PasswordsStore.StorePasswordForEvent(m.getId(), passHashed);
			return true;
		} else {
			return false;
		}
	}
}